﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace LoRel
{

    [TestClass]
    public class CoreSchemaTests
    {
        [TestMethod]
        public void TablesDerivedThroughColumnsAndKeys()
        {
            Core core = new Core();
            core.DeclareField("Symbol", typeof(String));
            core.DeclareField("Trader", typeof(String));
            core.DeclareField("Quantity", typeof(int));
            core.DeclareField("Price", typeof(double));

            core.DeclareColumn("Position", "Symbol");
            core.DeclareColumn("Position", "Trader");
            core.DeclareColumn("Position", "Quantity");

            core.DeclareKeys("Position", new[] { "Symbol", "Trader" });
            TableReference table = core.GetTable("Position");

            // TODO: fix assertions to not require index
            Assert.AreEqual(table.Columns[0].Name, "Symbol");
            Assert.AreEqual(table.Columns[1].Name, "Trader");
            Assert.AreEqual(table.Columns[2].Name, "Quantity");

            Assert.AreEqual(table.Keys.Columns[0].Name, "Symbol");
            Assert.AreEqual(table.Keys.Columns[1].Name, "Trader");
        }

        [TestMethod]
        public void ColumnNamesMapToExistingField()
        {
            Core core = new Core();
            try
            {
                core.DeclareColumn("Position", "Symbol");
            }
            catch (ArgumentOutOfRangeException ex)
            {
                return;
            }

            Assert.Fail("DeclareColumn accepted a Field that hasn't been registered");
        }

        [TestMethod]
        public void ColumnNamesMapToField()
        {
            Core core = new Core();
            FieldDeclaration field = core.DeclareField("Symbol", typeof(String));
            core.DeclareColumn("Position", "Symbol");

            ColumnReference column_reference = core.GetColumn("Position", "Symbol");
            Assert.AreSame(column_reference.Column.Field, field);
        }

        [TestMethod]
        public void PropertiesAreIComparable()
        {
            Core core = new Core();
            try
            {
                FieldDeclaration field = core.DeclareField("ShouldThrow", typeof(System.Threading.Thread));
            }
            catch (ArgumentException ex)
            {
                return;
            }

            Assert.Fail("Non IComparable Field Declaration did not throw");
        }

        [TestMethod]
        public void TableMustHaveKey()
        {
            Core core = new Core();

            core.DeclareField("Symbol", typeof(String));
            core.DeclareColumn("Position", "Symbol");
            try
            {
                core.GetTable("Position");
            }
            catch (InvalidStateException ex)
            {
                return;
            }
            Assert.Fail("GetTable returned a table that had no keys");
        }

        [TestMethod]
        public void KeysMustBeSubsetOfColumns()
        {
            Core core = new Core();

            core.DeclareField("Symbol", typeof(String));
            core.DeclareColumn("Position", "Symbol");
            try
            {
                core.DeclareKeys("Position", new[] { "Price" });
            }
            catch (ArgumentOutOfRangeException ex)
            {
                return;
            }
            Assert.Fail("DeclareKeys accepted keys outside of the declared columns.");
        }
    }
}
